{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configuration for Colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "IN_COLAB = \"google.colab\" in sys.modules\n",
    "\n",
    "if IN_COLAB:\n",
    "    !apt install python-opengl\n",
    "    !apt install ffmpeg\n",
    "    !apt install xvfb\n",
    "    !pip install pyvirtualdisplay\n",
    "    from pyvirtualdisplay import Display\n",
    "    \n",
    "    # Start virtual display\n",
    "    dis = Display(visible=0, size=(600, 400))\n",
    "    dis.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 06. DDPGfD\n",
    "\n",
    "[M. Vecerik et al., \"Leveraging Demonstrations for Deep Reinforcement Learning on Robotics Problems with Sparse Rewards.\"arXiv preprint arXiv:1707.08817, 2017](https://arxiv.org/pdf/1707.08817.pdf)\n",
    "\n",
    "ReinforcementLearning (RL) offers, in principle, a method to learn such policies from exploration, but the amount of actual exploration required has prohibited its use in real applications. In this paper the authors address this challenge by combining the demonstration and RL paradigms into a single framework which uses demonstrations to guide a deep-RL algorithm. \n",
    "\n",
    "The central contribution of this paper is to show that off-policy replay-memory-based RL (e.g. DDPG) is a natural vehicle for injecting demonstration data into sparse-reward tasks and that it obviates the need for reward-shaping. \n",
    "\n",
    "The algorithms called DDPG from Demonstration (*DDPGfD*) modifies DDPG to take advantage of demonstrations.\n",
    "\n",
    "### DDPG\n",
    "For learning in high-dimentional and continous action spaces, the authors of DDPG combine the actor-critic approach with insights from the success of DQN. Deep DPG(DDPG) is based on the deterministic policy gradient(DPG) algorithm ([Silver et al., 2014](http://proceedings.mlr.press/v32/silver14.pdf)). Please see *03.DDPG.ipynb* for detailed description of DDPG.\n",
    "\n",
    "### Prioritized Experience Replay (PER)\n",
    "Prioritized experience replay modifies the agent to sample more important transitions from its replay buffer more frequently.\n",
    "\n",
    "The probability of sampling a particular transition is proportional to its priority,\n",
    "$$\n",
    "P(i) = \\frac{p_i^{\\alpha}}{\\sum_k p_k^{\\alpha}}\n",
    "$$\n",
    ", where $p_i$ the priority of the transition. The priority is commonly to use the magnitude of a transition’s TD error.\n",
    "\n",
    "DDPGfD uses \n",
    "$$\n",
    "p_i = \\delta^{2}_{i} + \\lambda_3 |\\nabla_a Q(s_i, a_i|\\theta^Q)|^2 + \\epsilon + \\epsilon_D,\n",
    "$$\n",
    "- $\\delta_i$ is the last TD error calculated for this transition. The second term represents the loss applied to the actor.\n",
    "- $\\epsilon$ is a small positive constant to ensure all transitions are sampled with some probability.\n",
    "- $\\epsilon_D$ is a positive constant for demonstration transitions to increase their probability of getting sampled.\n",
    "- $\\lambda_3$ is used to weight the contributions.\n",
    "\n",
    "One more. Let's recall one of the main ideas of DQN. To remove correlation of observations, it uses uniformly random sampling from the replay buffer. Prioritized replay introduces bias because it doesn't sample experiences uniformly at random due to the sampling proportion correspoding to TD-error. We can correct this bias by using importance-sampling (IS) weights\n",
    "\n",
    "$$\n",
    "w_i = \\big( \\frac{1}{N} \\cdot \\frac{1}{P(i)} \\big)^\\beta\n",
    "$$\n",
    "\n",
    "that fully compensates for the non-uniform probabilities $P(i)$ if $\\beta = 1$. These weights can be folded into the Q-learning update by using $w_i\\delta_i$ instead of $\\delta_i$.\n",
    "\n",
    "For details, refer to the PER paper ([T. Schaul et al., 2015.](https://arxiv.org/pdf/1511.05952.pdf))\n",
    "\n",
    "### A mix of 1-step and n-step returns\n",
    "A modification for the sparse reward case is to use a mix of 1-step and n-step returns when updating the critic function. Incorporating *n-step returns* helps propagate the Q-values along the trajectories.\n",
    "\n",
    "The n-step return has the following form:\n",
    "$$\n",
    "R_n = \\sum^{n-1}_{i=0} \\gamma^i r_i + \\gamma^n Q(s'_{n-1}, \\pi(s'_{n-1}; \\theta^{Q'}))\n",
    "$$\n",
    "\n",
    "The loss corresponding to this particular rollout is then:\n",
    "$$\n",
    "L_n(\\theta^Q) = \\frac{1}{2} (R_n - Q(s, \\pi(s) | \\theta^Q))^2\n",
    "$$\n",
    "\n",
    "### Loss function\n",
    "The loss function is combined the above mentioned losses. Additionally *L2 regularization* on the parameters of the actor and the critic networks are added to stabilize the final learning performance. Two parameters called $\\lambda_1$, $\\lambda_2$ are used to weight the contributions.\n",
    "\n",
    "$$\n",
    "L_{Critic}(\\theta ^ Q) = L_1(\\theta^Q) + \\lambda_1 L_n(\\theta^Q) + \\lambda_2 L^{C}_{reg} (\\theta^Q)   \\\\\n",
    "$$\n",
    "$$\n",
    "\\nabla_{\\theta^{\\pi}} L_{Actor}(\\theta^\\pi) = - \\nabla_{\\theta^{\\pi}} J(\\theta^\\pi) + \\lambda_2 L^{A}_{reg} (\\theta^\\pi)\n",
    "$$\n",
    "\n",
    "### Pretrain\n",
    "We make use of the demonstration data to pre-train the agent so that it can perform well in the task from the start of learning, and then continue improving from its own self-generated data.\n",
    "\n",
    "Reference: \n",
    "- [Pseudo code of DDPGfD paper](https://arxiv.org/pdf/1707.08817.pdf)\n",
    "- [DQfD](https://arxiv.org/pdf/1704.03732)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import modules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import copy\n",
    "import random\n",
    "from collections import deque\n",
    "from typing import Deque, Dict, List, Tuple\n",
    "\n",
    "import gym\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "\n",
    "from IPython.display import clear_output\n",
    "\n",
    "if IN_COLAB and not os.path.exists(\"segment_tree.py\") and not os.path.exists(\"demo.pkl\"):\n",
    "    # download segment tree module\n",
    "    !wget https://raw.githubusercontent.com/mrsyee/pg-is-all-you-need/master/segment_tree.py\n",
    "    # download demo.pkl\n",
    "    !wget https://raw.githubusercontent.com/mrsyee/pg-is-all-you-need/master/demo.pkl\n",
    "        \n",
    "from segment_tree import MinSegmentTree, SumSegmentTree"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set random seed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "if torch.backends.cudnn.enabled:\n",
    "    torch.backends.cudnn.benchmark = False\n",
    "    torch.backends.cudnn.deterministic = True\n",
    "\n",
    "seed = 777\n",
    "torch.manual_seed(seed)\n",
    "np.random.seed(seed)\n",
    "random.seed(seed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Replay buffer for N-step learning with demonstration\n",
    "\n",
    "There are a little bit changes in Replay buffer for N-step learning with demonstration.\n",
    "\n",
    "First, we use `deque` to store the most recent n-step transitions.\n",
    "\n",
    "```python\n",
    "    self.n_step_buffer = deque(maxlen=n_step)\n",
    "```\n",
    "\n",
    "You can see it doesn't actually store a transition in the buffer, unless `n_step_buffer` is full.\n",
    "\n",
    "```\n",
    "    # in store method\n",
    "    if len(self.n_step_buffer) < self.n_step:\n",
    "        return ()\n",
    "```\n",
    "\n",
    "When the length of `n_step_buffer` becomes equal to N, it eventually stores the N-step transition, which is calculated by `get_n_step_info` method (reference `util.py`). Furthermore, there are additional implementations for saving loaded demos. (Please see *03.DDPG.ipynb* for detailed description of the basic replay buffer.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReplayBuffer:\n",
    "    \"\"\"A numpy replay buffer with demonstrations.\"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        obs_dim: int, \n",
    "        size: int, \n",
    "        batch_size: int = 32, \n",
    "        gamma: float = 0.99,\n",
    "        demo: list = None,\n",
    "        n_step: int = 1, \n",
    "    ):\n",
    "        \"\"\"Initialize.\"\"\"\n",
    "        self.obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.next_obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.acts_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.rews_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.done_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.max_size, self.batch_size = size, batch_size\n",
    "        self.ptr, self.size = 0, 0\n",
    "        \n",
    "        # for N-step Learning\n",
    "        self.n_step_buffer = deque(maxlen=n_step)\n",
    "        self.n_step = n_step\n",
    "        self.gamma = gamma\n",
    "        \n",
    "        # for demonstration\n",
    "        self.demo_size = len(demo) if demo else 0\n",
    "        self.demo = demo\n",
    "        \n",
    "        if self.demo:\n",
    "            self.ptr += self.demo_size\n",
    "            self.size += self.demo_size\n",
    "            for ptr, d in enumerate(self.demo):\n",
    "                state, action, reward, next_state, done = d\n",
    "                self.obs_buf[ptr] = state\n",
    "                self.acts_buf[ptr] = np.array(action)\n",
    "                self.rews_buf[ptr] = reward\n",
    "                self.next_obs_buf[ptr] = next_state\n",
    "                self.done_buf[ptr] = done\n",
    "\n",
    "    def store(\n",
    "        self,\n",
    "        obs: np.ndarray,\n",
    "        act: np.ndarray, \n",
    "        rew: float, \n",
    "        next_obs: np.ndarray, \n",
    "        done: bool,\n",
    "    ) -> Tuple[np.ndarray, np.ndarray, float, np.ndarray, bool]:\n",
    "        \"\"\"Store the transition in buffer.\"\"\"\n",
    "        transition = (obs, act, rew, next_obs, done)\n",
    "        self.n_step_buffer.append(transition)\n",
    "        \n",
    "        # single step transition is not ready\n",
    "        if len(self.n_step_buffer) < self.n_step:\n",
    "            return ()\n",
    "        \n",
    "        # make a n-step transition\n",
    "        rew, next_obs, done = self._get_n_step_info()\n",
    "        obs, act = self.n_step_buffer[0][:2]\n",
    "        \n",
    "        self.obs_buf[self.ptr] = obs\n",
    "        self.next_obs_buf[self.ptr] = next_obs\n",
    "        self.acts_buf[self.ptr] = act\n",
    "        self.rews_buf[self.ptr] = rew\n",
    "        self.done_buf[self.ptr] = done\n",
    "        \n",
    "        self.ptr += 1\n",
    "        self.ptr = self.demo_size if self.ptr % self.max_size == 0 else self.ptr\n",
    "        self.size = min(self.size + 1, self.max_size)\n",
    "        \n",
    "        return self.n_step_buffer[0]\n",
    "\n",
    "    def sample_batch(self, indices: List[int] = None) -> Dict[str, np.ndarray]:\n",
    "        \"\"\"Randomly sample a batch of experiences from memory.\"\"\"\n",
    "        assert len(self) >= self.batch_size\n",
    "        \n",
    "        if indices is None:\n",
    "            indices = np.random.choice(\n",
    "                len(self), size=self.batch_size, replace=False\n",
    "            )\n",
    "            \n",
    "        return dict(\n",
    "            obs=self.obs_buf[indices],\n",
    "            next_obs=self.next_obs_buf[indices],\n",
    "            acts=self.acts_buf[indices],\n",
    "            rews=self.rews_buf[indices],\n",
    "            done=self.done_buf[indices],\n",
    "            # for N-step learning\n",
    "            indices=indices,\n",
    "        )\n",
    "    \n",
    "    def _get_n_step_info(self) -> Tuple[np.int64, np.ndarray, bool]:\n",
    "        \"\"\"Return n step rew, next_obs, and done.\"\"\"\n",
    "        # info of the last transition\n",
    "        rew, next_obs, done = self.n_step_buffer[-1][-3:]\n",
    "\n",
    "        for transition in reversed(list(self.n_step_buffer)[:-1]):\n",
    "            r, n_o, d = transition[-3:]\n",
    "\n",
    "            rew = r + self.gamma * rew * (1 - d)\n",
    "            next_obs, done = (n_o, d) if d else (next_obs, done)\n",
    "\n",
    "        return rew, next_obs, done\n",
    "\n",
    "    def __len__(self) -> int:\n",
    "        return self.size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prioritized replay Buffer with demonstration\n",
    "\n",
    "The key concept of PER's implementation is *Segment Tree*. It efficiently stores and samples transitions while managing the priorities of them (reference `segment_tree.py`). We recommend you understand how it works before you move on. Here are references for you:\n",
    "\n",
    "- In Korean: https://mrsyee.github.io/rl/2019/01/25/PER-sumtree/\n",
    "- In English: https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/\n",
    "\n",
    "In addtion, `epsilon_d` is a positive constant for demonstration transitions to increase their probability of getting sampled."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PrioritizedReplayBuffer(ReplayBuffer):\n",
    "    \"\"\"Prioritized Replay buffer with demonstrations.\"\"\"\n",
    "    \n",
    "    def __init__(\n",
    "        self, \n",
    "        obs_dim: int,\n",
    "        size: int, \n",
    "        batch_size: int = 32, \n",
    "        gamma: float = 0.99,\n",
    "        alpha: float = 0.6,\n",
    "        epsilon_d: float = 1.0,\n",
    "        demo: list = None,\n",
    "    ):\n",
    "        \"\"\"Initialize.\"\"\"\n",
    "        assert alpha >= 0\n",
    "        \n",
    "        super(PrioritizedReplayBuffer, self).__init__(\n",
    "            obs_dim, size, batch_size, gamma, demo, n_step=1 \n",
    "        )\n",
    "        self.max_priority, self.tree_ptr = 1.0, 0\n",
    "        self.alpha = alpha\n",
    "        self.epsilon_d = epsilon_d\n",
    "        \n",
    "        # capacity must be positive and a power of 2.\n",
    "        tree_capacity = 1\n",
    "        while tree_capacity < self.max_size:\n",
    "            tree_capacity *= 2\n",
    "\n",
    "        self.sum_tree = SumSegmentTree(tree_capacity)\n",
    "        self.min_tree = MinSegmentTree(tree_capacity)\n",
    "        \n",
    "        # for init priority of demo\n",
    "        self.tree_ptr = self.demo_size\n",
    "        for i in range(self.demo_size):\n",
    "            self.sum_tree[i] = self.max_priority ** self.alpha\n",
    "            self.min_tree[i] = self.max_priority ** self.alpha\n",
    "        \n",
    "    def store(\n",
    "        self, \n",
    "        obs: np.ndarray, \n",
    "        act: int, \n",
    "        rew: float, \n",
    "        next_obs: np.ndarray, \n",
    "        done: bool\n",
    "    ):\n",
    "        \"\"\"Store experience and priority.\"\"\"\n",
    "        transition = super().store(obs, act, rew, next_obs, done)\n",
    "        \n",
    "        if transition:\n",
    "            self.sum_tree[self.tree_ptr] = self.max_priority ** self.alpha\n",
    "            self.min_tree[self.tree_ptr] = self.max_priority ** self.alpha\n",
    "\n",
    "            self.tree_ptr += 1\n",
    "            if self.tree_ptr % self.max_size == 0:\n",
    "                self.tree_ptr = self.demo_size\n",
    "            \n",
    "        return transition\n",
    "\n",
    "    def sample_batch(self, beta: float = 0.4) -> Dict[str, np.ndarray]:\n",
    "        \"\"\"Sample a batch of experiences.\"\"\"\n",
    "        assert len(self) >= self.batch_size\n",
    "        assert beta > 0\n",
    "        \n",
    "        indices = self._sample_proportional()\n",
    "        \n",
    "        obs = self.obs_buf[indices]\n",
    "        next_obs = self.next_obs_buf[indices]\n",
    "        acts = self.acts_buf[indices]\n",
    "        rews = self.rews_buf[indices]\n",
    "        done = self.done_buf[indices]\n",
    "        weights = np.array([self._calculate_weight(i, beta) for i in indices])\n",
    "        epsilon_d = np.array(\n",
    "            [self.epsilon_d if i < self.demo_size else 0.0 for i in indices]\n",
    "        )\n",
    "        \n",
    "        return dict(\n",
    "            obs=obs,\n",
    "            next_obs=next_obs,\n",
    "            acts=acts,\n",
    "            rews=rews,\n",
    "            done=done,\n",
    "            weights=weights,\n",
    "            epsilon_d=epsilon_d,\n",
    "            indices=indices,\n",
    "        )\n",
    "        \n",
    "    def update_priorities(self, indices: List[int], priorities: np.ndarray):\n",
    "        \"\"\"Update priorities of sampled transitions.\"\"\"\n",
    "        assert len(indices) == len(priorities)\n",
    "\n",
    "        for idx, priority in zip(indices, priorities):\n",
    "            assert priority > 0\n",
    "            assert 0 <= idx < len(self)\n",
    "\n",
    "            self.sum_tree[idx] = priority ** self.alpha\n",
    "            self.min_tree[idx] = priority ** self.alpha\n",
    "\n",
    "            self.max_priority = max(self.max_priority, priority)\n",
    "            \n",
    "    def _sample_proportional(self) -> List[int]:\n",
    "        \"\"\"Sample indices based on proportions.\"\"\"\n",
    "        indices = []\n",
    "        p_total = self.sum_tree.sum(0, len(self) - 1)\n",
    "        segment = p_total / self.batch_size\n",
    "        \n",
    "        for i in range(self.batch_size):\n",
    "            a = segment * i\n",
    "            b = segment * (i + 1)\n",
    "            upperbound = random.uniform(a, b)\n",
    "            idx = self.sum_tree.retrieve(upperbound)\n",
    "            indices.append(idx)\n",
    "            \n",
    "        return indices\n",
    "    \n",
    "    def _calculate_weight(self, idx: int, beta: float):\n",
    "        \"\"\"Calculate the weight of the experience at idx.\"\"\"\n",
    "        # get max weight\n",
    "        p_min = self.min_tree.min() / self.sum_tree.sum()\n",
    "        max_weight = (p_min * len(self)) ** (-beta)\n",
    "        \n",
    "        # calculate weights\n",
    "        p_sample = self.sum_tree[idx] / self.sum_tree.sum()\n",
    "        weight = (p_sample * len(self)) ** (-beta)\n",
    "        weight = weight / max_weight\n",
    "        \n",
    "        return weight"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## OU Noise\n",
    "*Ornstein-Uhlenbeck* process generates temporally correlated exploration, and it effectively copes with physical control problems of inertia.\n",
    "\n",
    "$$\n",
    "dx_t = \\theta(\\mu - x_t) dt + \\sigma dW_t\n",
    "$$\n",
    "\n",
    "Reference: \n",
    "- [Udacity github](https://github.com/udacity/deep-reinforcement-learning/blob/master/ddpg-pendulum/ddpg_agent.py)\n",
    "- [Wiki](https://en.wikipedia.org/wiki/Ornstein%E2%80%93Uhlenbeck_process)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class OUNoise:\n",
    "    \"\"\"Ornstein-Uhlenbeck process.\n",
    "    Taken from Udacity deep-reinforcement-learning github repository:\n",
    "    https://github.com/udacity/deep-reinforcement-learning/blob/master/\n",
    "    ddpg-pendulum/ddpg_agent.py\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        size: int, \n",
    "        mu: float = 0.0, \n",
    "        theta: float = 0.15, \n",
    "        sigma: float = 0.2,\n",
    "    ):\n",
    "        \"\"\"Initialize parameters and noise process.\"\"\"\n",
    "        self.state = np.float64(0.0)\n",
    "        self.mu = mu * np.ones(size)\n",
    "        self.theta = theta\n",
    "        self.sigma = sigma\n",
    "        self.reset()\n",
    "\n",
    "    def reset(self):\n",
    "        \"\"\"Reset the internal state (= noise) to mean (mu).\"\"\"\n",
    "        self.state = copy.copy(self.mu)\n",
    "\n",
    "    def sample(self) -> np.ndarray:\n",
    "        \"\"\"Update internal state and return it as a noise sample.\"\"\"\n",
    "        x = self.state\n",
    "        dx = self.theta * (self.mu - x) + self.sigma * np.array(\n",
    "            [random.random() for _ in range(len(x))]\n",
    "        )\n",
    "        self.state = x + dx\n",
    "        return self.state"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Network\n",
    "We are going to use two separated networks for actor and critic. The actor network has three fully connected layers and three non-linearity functions, *ReLU* for hidden layers and *tanh* for the output layer. On the other hand, the critic network has three fully connected layers, but it used two activation functions for hidden layers *ReLU*. Plus, its input sizes of critic network are sum of state sizes and action sizes. One thing to note is that we initialize the final layer's weights and biases so that they are *uniformly distributed.*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Actor(nn.Module):\n",
    "    def __init__(\n",
    "        self, \n",
    "        in_dim: int, \n",
    "        out_dim: int,\n",
    "        init_w: float = 3e-3,\n",
    "    ):\n",
    "        \"\"\"Initialize.\"\"\"\n",
    "        super(Actor, self).__init__()\n",
    "        \n",
    "        self.hidden1 = nn.Linear(in_dim, 128)\n",
    "        self.hidden2 = nn.Linear(128, 128)\n",
    "        self.out = nn.Linear(128, out_dim)\n",
    "        \n",
    "        self.out.weight.data.uniform_(-init_w, init_w)\n",
    "        self.out.bias.data.uniform_(-init_w, init_w)\n",
    "\n",
    "    def forward(self, state: torch.Tensor) -> torch.Tensor:\n",
    "        \"\"\"Forward method implementation.\"\"\"\n",
    "        x = F.relu(self.hidden1(state))\n",
    "        x = F.relu(self.hidden2(x))\n",
    "        action = self.out(x).tanh()\n",
    "        \n",
    "        return action\n",
    "    \n",
    "    \n",
    "class Critic(nn.Module):\n",
    "    def __init__(\n",
    "        self, \n",
    "        in_dim: int, \n",
    "        init_w: float = 3e-3,\n",
    "    ):\n",
    "        \"\"\"Initialize.\"\"\"\n",
    "        super(Critic, self).__init__()\n",
    "        \n",
    "        self.hidden1 = nn.Linear(in_dim, 128)\n",
    "        self.hidden2 = nn.Linear(128, 128)\n",
    "        self.out = nn.Linear(128, 1)\n",
    "        \n",
    "        self.out.weight.data.uniform_(-init_w, init_w)\n",
    "        self.out.bias.data.uniform_(-init_w, init_w)\n",
    "\n",
    "    def forward(\n",
    "        self, state: torch.Tensor, action: torch.Tensor\n",
    "    ) -> torch.Tensor:\n",
    "        \"\"\"Forward method implementation.\"\"\"\n",
    "        x = torch.cat((state, action), dim=-1)\n",
    "        x = F.relu(self.hidden1(x))\n",
    "        x = F.relu(self.hidden2(x))\n",
    "        value = self.out(x)\n",
    "        \n",
    "        return value"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DDPGfD Agent\n",
    "Here is a summary of DDPGfDAgent class.\n",
    "\n",
    "| Method           | Note                                                 |\n",
    "|---               |---                                                  |\n",
    "|select_action     | select an action from the input state.               |\n",
    "|step              | take an action and return the response of the env.   |\n",
    "|update_model      | update the model by gradient descent.                |\n",
    "|train             | train the agent during num_frames.                   |\n",
    "|test              | test the agent (1 episode).                          |\n",
    "|\\_pretrain        |pretraining steps.|\n",
    "|\\_get_critic_loss   | return element-wise critic loss.                     |\n",
    "|\\_target_soft_update| soft update from the local model to the target model.|\n",
    "|\\_get_n_step_info_from_demo | return 1 step and n step demos. |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DDPGfDAgent:\n",
    "    \"\"\"DDPGfDAgent interacting with environment.\n",
    "    \n",
    "    Attribute:\n",
    "        env (gym.Env): openAI Gym environment\n",
    "        actor (nn.Module): target actor model to select actions\n",
    "        actor_target (nn.Module): actor model to predict next actions\n",
    "        actor_optimizer (Optimizer): optimizer for training actor\n",
    "        critic (nn.Module): critic model to predict state values\n",
    "        critic_target (nn.Module): target critic model to predict state values\n",
    "        critic_optimizer (Optimizer): optimizer for training critic\n",
    "        demo (list): demonstration\n",
    "        memory (ReplayBuffer): replay memory to store transitions\n",
    "        batch_size (int): batch size for sampling\n",
    "        gamma (float): discount factor\n",
    "        tau (float): parameter for soft target update\n",
    "        initial_random_steps (int): initial random action steps\n",
    "        pretrain_step (int): the number of step for pre-training\n",
    "        n_step (int): the number of multi step\n",
    "        use_n_step (bool): whether to use n_step memory\n",
    "        prior_eps (float): guarantees every transitions can be sampled\n",
    "        lambda1 (float): n-step return weight\n",
    "        lambda2 (float): l2 regularization weight\n",
    "        lambda3 (float): actor loss contribution of prior weight\n",
    "        noise (OUNoise): noise generator for exploration\n",
    "        device (torch.device): cpu / gpu\n",
    "        transition (list): temporory storage for the recent transition\n",
    "        total_step (int): total step numbers\n",
    "        is_test (bool): flag to show the current mode (train / test)\n",
    "    \"\"\"\n",
    "    def __init__(\n",
    "        self,\n",
    "        env: gym.Env,\n",
    "        memory_size: int,\n",
    "        batch_size: int,\n",
    "        ou_noise_theta: float,\n",
    "        ou_noise_sigma: float,\n",
    "        demo: list,\n",
    "        pretrain_step: int,\n",
    "        gamma: float = 0.99,\n",
    "        tau: float = 5e-3,\n",
    "        initial_random_steps: int = 1e4,\n",
    "        # PER parameters\n",
    "        alpha: float = 0.3,\n",
    "        beta: float = 1.0,\n",
    "        prior_eps: float = 1e-6,\n",
    "        # N-step Learning\n",
    "        n_step: int = 3,\n",
    "        # loss parameters\n",
    "        lambda1: float = 1.0, # N-step return weight\n",
    "        lambda2: float = 1e-4, # l2 regularization weight\n",
    "        lambda3: float = 1.0, # actor loss contribution of prior weight\n",
    "    ):\n",
    "        \"\"\"Initialize.\"\"\"\n",
    "        obs_dim = env.observation_space.shape[0]\n",
    "        action_dim = env.action_space.shape[0]\n",
    "\n",
    "        self.env = env\n",
    "        self.batch_size = batch_size\n",
    "        self.pretrain_step = pretrain_step\n",
    "        self.gamma = gamma\n",
    "        self.tau = tau\n",
    "        self.initial_random_steps = initial_random_steps\n",
    "        self.lambda1 = lambda1\n",
    "        self.lambda3 = lambda3\n",
    "        \n",
    "        self.demo = demo\n",
    "        demos_1_step, demos_n_step = [], []\n",
    "        if self.demo:\n",
    "            demos_1_step, demos_n_step = self._get_n_step_info_from_demo(\n",
    "                demo, n_step\n",
    "            )\n",
    "        \n",
    "        # PER\n",
    "        # memory for 1-step Learning\n",
    "        self.beta = beta\n",
    "        self.prior_eps = prior_eps\n",
    "        self.memory = PrioritizedReplayBuffer(\n",
    "            obs_dim, memory_size, batch_size, gamma, alpha, demo=demos_1_step\n",
    "        )\n",
    "        \n",
    "        # memory for N-step Learning\n",
    "        self.use_n_step = True if n_step > 1 else False\n",
    "        if self.use_n_step:\n",
    "            self.n_step = n_step\n",
    "            self.memory_n = ReplayBuffer(\n",
    "                obs_dim, \n",
    "                memory_size, \n",
    "                batch_size, \n",
    "                gamma, \n",
    "                demos_n_step, \n",
    "                self.n_step\n",
    "            )\n",
    "                \n",
    "        # noise\n",
    "        self.noise = OUNoise(\n",
    "            action_dim,\n",
    "            theta=ou_noise_theta,\n",
    "            sigma=ou_noise_sigma,\n",
    "        )\n",
    "\n",
    "        # device: cpu / gpu\n",
    "        self.device = torch.device(\n",
    "            \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
    "        )\n",
    "        print(self.device)\n",
    "\n",
    "        # networks\n",
    "        self.actor = Actor(obs_dim, action_dim).to(self.device)\n",
    "        self.actor_target = Actor(obs_dim, action_dim).to(self.device)\n",
    "        self.actor_target.load_state_dict(self.actor.state_dict())\n",
    "        \n",
    "        self.critic = Critic(obs_dim + action_dim).to(self.device)\n",
    "        self.critic_target = Critic(obs_dim + action_dim).to(self.device)\n",
    "        self.critic_target.load_state_dict(self.critic.state_dict())\n",
    "\n",
    "        # optimizer\n",
    "        self.actor_optimizer = optim.Adam(\n",
    "            self.actor.parameters(),\n",
    "            lr=3e-4,\n",
    "            weight_decay=lambda2,\n",
    "        )\n",
    "        self.critic_optimizer = optim.Adam(\n",
    "            self.critic.parameters(),\n",
    "            lr=1e-3,\n",
    "            weight_decay=lambda2,\n",
    "        )\n",
    "        \n",
    "        # transition to store in memory\n",
    "        self.transition = list()\n",
    "        \n",
    "        # total steps count\n",
    "        self.total_step = 0\n",
    "\n",
    "        # mode: train / test\n",
    "        self.is_test = False\n",
    "    \n",
    "    def select_action(self, state: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"Select an action from the input state.\"\"\"\n",
    "        # if initial random action should be conducted\n",
    "        if self.total_step < self.initial_random_steps and not self.is_test:\n",
    "            selected_action = self.env.action_space.sample()\n",
    "        else:\n",
    "            selected_action = self.actor(\n",
    "                torch.FloatTensor(state).to(self.device)\n",
    "            ).detach().cpu().numpy()\n",
    "        \n",
    "        # add noise for exploration during training\n",
    "        if not self.is_test:\n",
    "            noise = self.noise.sample()\n",
    "            selected_action = np.clip(selected_action + noise, -1.0, 1.0)\n",
    "        \n",
    "        self.transition = [state, selected_action]\n",
    "        \n",
    "        return selected_action\n",
    "    \n",
    "    def step(self, action: np.ndarray) -> Tuple[np.ndarray, np.float64, bool]:\n",
    "        \"\"\"Take an action and return the response of the env.\"\"\"\n",
    "        next_state, reward, done, _ = self.env.step(action)\n",
    "        \n",
    "        if not self.is_test:\n",
    "            self.transition += [reward, next_state, done]\n",
    "            \n",
    "            # N-step transition\n",
    "            transition = self.transition\n",
    "            if self.use_n_step:\n",
    "                transition = self.memory_n.store(*self.transition)\n",
    "\n",
    "            # add a single step transition\n",
    "            if transition:\n",
    "                self.memory.store(*transition)\n",
    "    \n",
    "        return next_state, reward, done\n",
    "    \n",
    "    def update_model(self) -> Tuple[torch.Tensor, ...]:\n",
    "        \"\"\"Update the model by gradient descent.\"\"\"\n",
    "        device = self.device  # for shortening the following lines\n",
    "        \n",
    "        samples = self.memory.sample_batch(self.beta)        \n",
    "        state = torch.FloatTensor(samples[\"obs\"]).to(device)\n",
    "        action = torch.FloatTensor(samples[\"acts\"].reshape(-1, 1)).to(device)\n",
    "\n",
    "        weights = torch.FloatTensor(\n",
    "            samples[\"weights\"].reshape(-1, 1)\n",
    "        ).to(device)\n",
    "        epsilon_d = samples[\"epsilon_d\"]\n",
    "        indices = samples[\"indices\"]\n",
    "        \n",
    "        # train critic\n",
    "        # 1-step loss\n",
    "        critic_loss_element_wise = self._get_critic_loss(samples, self.gamma)\n",
    "        critic_loss = torch.mean(critic_loss_element_wise * weights)\n",
    "        \n",
    "        # n-step loss\n",
    "        if self.use_n_step:\n",
    "            samples_n = self.memory_n.sample_batch(indices)\n",
    "            n_gamma = self.gamma ** self.n_step\n",
    "            critic_loss_n_element_wise = self._get_critic_loss(\n",
    "                samples_n, n_gamma\n",
    "            )\n",
    "            \n",
    "            # to update loss and priorities\n",
    "            critic_loss_element_wise += (\n",
    "                critic_loss_n_element_wise * self.lambda1\n",
    "            )\n",
    "            critic_loss = torch.mean(critic_loss_element_wise * weights) \n",
    "        \n",
    "        self.critic_optimizer.zero_grad()\n",
    "        critic_loss.backward()\n",
    "        self.critic_optimizer.step()\n",
    "                \n",
    "        # train actor\n",
    "        actor_loss_element_wise = -self.critic(state, self.actor(state))\n",
    "        actor_loss = torch.mean(actor_loss_element_wise * weights)\n",
    "        \n",
    "        self.actor_optimizer.zero_grad()\n",
    "        actor_loss.backward()\n",
    "        self.actor_optimizer.step()\n",
    "        \n",
    "        # target update\n",
    "        self._target_soft_update()\n",
    "        \n",
    "        # PER: update priorities\n",
    "        new_priorities = critic_loss_element_wise\n",
    "        new_priorities += self.lambda3 * actor_loss_element_wise.pow(2)\n",
    "        new_priorities += self.prior_eps\n",
    "        new_priorities = new_priorities.data.cpu().numpy().squeeze()\n",
    "        new_priorities += epsilon_d\n",
    "        self.memory.update_priorities(indices, new_priorities)\n",
    "        \n",
    "        # check the number of sampling demos\n",
    "        demo_idxs = np.where(epsilon_d != 0.0)\n",
    "        n_demo = demo_idxs[0].size\n",
    "        \n",
    "        return actor_loss.data, critic_loss.data, n_demo\n",
    "    \n",
    "    def _pretrain(self) -> Tuple[List[torch.Tensor], List[torch.Tensor]]:\n",
    "        \"\"\"Pretraining steps.\"\"\"\n",
    "        actor_losses = []\n",
    "        critic_losses = []\n",
    "        print(\"Pre-Train %d step.\" % self.pretrain_step)\n",
    "        for _ in range(1, self.pretrain_step + 1):\n",
    "            actor_loss, critic_loss, _ = self.update_model()\n",
    "            actor_losses.append(actor_loss.data)\n",
    "            critic_losses.append(critic_loss.data)\n",
    "        print(\"Pre-Train Complete!\\n\")\n",
    "        return actor_losses, critic_losses\n",
    "    \n",
    "    def train(self, num_frames: int, plotting_interval: int = 200):\n",
    "        \"\"\"Train the agent.\"\"\"\n",
    "        self.is_test = False\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        actor_losses, critic_losses, n_demo_list, scores = [], [], [], []\n",
    "        score = 0\n",
    "        \n",
    "        if self.demo:\n",
    "            output = self._pretrain()\n",
    "            actor_losses.extend(output[0])\n",
    "            critic_losses.extend(output[1])\n",
    "        \n",
    "        for self.total_step in range(1, num_frames + 1):\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "            \n",
    "            # PER: increase beta\n",
    "            fraction = min(self.total_step / num_frames, 1.0)\n",
    "            self.beta = self.beta + fraction * (1.0 - self.beta)\n",
    "\n",
    "            # if episode ends\n",
    "            if done:         \n",
    "                state = env.reset()\n",
    "                scores.append(score)\n",
    "                score = 0\n",
    "\n",
    "            # if training is ready\n",
    "            if (\n",
    "                len(self.memory) >= self.batch_size \n",
    "                and self.total_step > self.initial_random_steps\n",
    "            ):\n",
    "                actor_loss, critic_loss, n_demo = self.update_model()\n",
    "                actor_losses.append(actor_loss)\n",
    "                critic_losses.append(critic_loss)\n",
    "                n_demo_list.append(n_demo)\n",
    "            \n",
    "            # plotting\n",
    "            if self.total_step % plotting_interval == 0:\n",
    "                self._plot(\n",
    "                    self.total_step, \n",
    "                    scores, \n",
    "                    actor_losses, \n",
    "                    critic_losses,\n",
    "                    n_demo_list,\n",
    "                )\n",
    "                \n",
    "        self.env.close()\n",
    "        \n",
    "    def test(self):\n",
    "        \"\"\"Test the agent.\"\"\"\n",
    "        self.is_test = True\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        done = False\n",
    "        score = 0\n",
    "        \n",
    "        frames = []\n",
    "        while not done:\n",
    "            frames.append(self.env.render(mode=\"rgb_array\"))\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "        \n",
    "        print(\"score: \", score)\n",
    "        self.env.close()\n",
    "        \n",
    "        return frames\n",
    "    \n",
    "    def _get_critic_loss(\n",
    "        self, samples: Dict[str, np.ndarray], gamma: float\n",
    "    ) -> torch.Tensor:\n",
    "        \"\"\"Return element-wise critic loss.\"\"\"\n",
    "        device = self.device  # for shortening the following lines\n",
    "        \n",
    "        state = torch.FloatTensor(samples[\"obs\"]).to(device)\n",
    "        next_state = torch.FloatTensor(samples[\"next_obs\"]).to(device)\n",
    "        action = torch.FloatTensor(samples[\"acts\"].reshape(-1, 1)).to(device)\n",
    "        reward = torch.FloatTensor(samples[\"rews\"].reshape(-1, 1)).to(device)\n",
    "        done = torch.FloatTensor(samples[\"done\"].reshape(-1, 1)).to(device)\n",
    "        \n",
    "        masks = 1 - done\n",
    "        next_action = self.actor_target(next_state)\n",
    "        next_value = self.critic_target(next_state, next_action)\n",
    "        curr_return = reward + gamma * next_value * masks\n",
    "        curr_return = curr_return.to(device).detach()\n",
    "\n",
    "        # train critic\n",
    "        values = self.critic(state, action)\n",
    "        critic_loss_element_wise = (values - curr_return).pow(2)\n",
    "\n",
    "        return critic_loss_element_wise\n",
    "    \n",
    "    def _target_soft_update(self):\n",
    "        \"\"\"Soft-update: target = tau*local + (1-tau)*target.\"\"\"\n",
    "        tau = self.tau\n",
    "        \n",
    "        for t_param, l_param in zip(\n",
    "            self.actor_target.parameters(), self.actor.parameters()\n",
    "        ):\n",
    "            t_param.data.copy_(tau * l_param.data + (1.0 - tau) * t_param.data)\n",
    "            \n",
    "        for t_param, l_param in zip(\n",
    "            self.critic_target.parameters(), self.critic.parameters()\n",
    "        ):\n",
    "            t_param.data.copy_(tau * l_param.data + (1.0 - tau) * t_param.data)\n",
    "    \n",
    "    def _get_n_step_info_from_demo(\n",
    "        self, demo: List, n_step: int\n",
    "    ) -> Tuple[List, List]:\n",
    "        \"\"\"Return 1 step and n step demos.\"\"\"\n",
    "        demos_1_step = list()\n",
    "        demos_n_step = list()\n",
    "        n_step_buffer: Deque = deque(maxlen=n_step)\n",
    "\n",
    "        for transition in demo:\n",
    "            n_step_buffer.append(transition)\n",
    "\n",
    "            if len(n_step_buffer) == n_step:\n",
    "                # add a single step transition\n",
    "                demos_1_step.append(n_step_buffer[0])\n",
    "\n",
    "                # add a multi step transition\n",
    "                curr_state, action = n_step_buffer[0][:2]\n",
    "                \n",
    "                # get n-step info\n",
    "                reward, next_state, done = n_step_buffer[-1][-3:]\n",
    "                for transition in reversed(list(n_step_buffer)[:-1]):\n",
    "                    r, n_o, d = transition[-3:]\n",
    "\n",
    "                    reward = r + self.gamma * reward * (1 - d)\n",
    "                    next_state, done = (n_o, d) if d else (next_state, done)\n",
    "                \n",
    "                transition = (curr_state, action, reward, next_state, done)\n",
    "                demos_n_step.append(transition)\n",
    "\n",
    "        return demos_1_step, demos_n_step\n",
    "    \n",
    "    def _plot(\n",
    "        self, \n",
    "        frame_idx: int, \n",
    "        scores: List[float], \n",
    "        actor_losses: List[float], \n",
    "        critic_losses: List[float], \n",
    "        n_demo: List[int],\n",
    "    ):\n",
    "        \"\"\"Plot the training progresses.\"\"\"\n",
    "        def subplot(loc: int, title: str, values: List[float]):\n",
    "            plt.subplot(loc)\n",
    "            plt.title(title)\n",
    "            plt.plot(values)\n",
    "                   \n",
    "        subplot_params = [\n",
    "            (141, f\"frame {frame_idx}. score: {np.mean(scores[-10:])}\", scores),\n",
    "            (142, \"actor_loss\", actor_losses),\n",
    "            (143, \"critic_loss\", critic_losses),\n",
    "            (144, \"the number of sampling demos\", n_demo),\n",
    "        ]\n",
    "        \n",
    "        clear_output(True)\n",
    "        plt.figure(figsize=(30, 5))            \n",
    "        for loc, title, values in subplot_params:\n",
    "            subplot(loc, title, values)\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Environment\n",
    "*ActionNormalizer* is an action wrapper class to normalize the action values ranged in (-1. 1). Thanks to this class, we can make the agent simply select action values within the zero centered range (-1, 1)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ActionNormalizer(gym.ActionWrapper):\n",
    "    \"\"\"Rescale and relocate the actions.\"\"\"\n",
    "\n",
    "    def action(self, action: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"Change the range (-1, 1) to (low, high).\"\"\"\n",
    "        low = self.action_space.low\n",
    "        high = self.action_space.high\n",
    "\n",
    "        scale_factor = (high - low) / 2\n",
    "        reloc_factor = high - scale_factor\n",
    "\n",
    "        action = action * scale_factor + reloc_factor\n",
    "        action = np.clip(action, low, high)\n",
    "\n",
    "        return action\n",
    "\n",
    "    def reverse_action(self, action: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"Change the range (low, high) to (-1, 1).\"\"\"\n",
    "        low = self.action_space.low\n",
    "        high = self.action_space.high\n",
    "\n",
    "        scale_factor = (high - low) / 2\n",
    "        reloc_factor = high - scale_factor\n",
    "\n",
    "        action = (action - reloc_factor) / scale_factor\n",
    "        action = np.clip(action, -1.0, 1.0)\n",
    "\n",
    "        return action"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see [the code](https://github.com/openai/gym/blob/master/gym/envs/classic_control/pendulum.py) and [configurations](https://github.com/openai/gym/blob/cedecb35e3428985fd4efad738befeb75b9077f1/gym/envs/__init__.py#L81) of Pendulum-v0 from OpenAI's repository."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/khkim/anaconda3/envs/pg-is-all-you-need/lib/python3.6/site-packages/gym/logger.py:30: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n",
      "  warnings.warn(colorize('%s: %s'%('WARN', msg % args), 'yellow'))\n"
     ]
    }
   ],
   "source": [
    "# environment\n",
    "env_id = \"Pendulum-v0\"\n",
    "env = gym.make(env_id)\n",
    "env = ActionNormalizer(env)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize\n",
    "We make the demonstration using the well-trained agent in advance. (The given demo.pkl is created transitions using *03.DDPG* agent.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "\n",
    "# load demo on replay memory\n",
    "demo_path = \"demo.pkl\"\n",
    "with open(demo_path, \"rb\") as f:\n",
    "    demo = pickle.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cpu\n"
     ]
    }
   ],
   "source": [
    "# parameters\n",
    "num_frames = 50000\n",
    "memory_size = 100000\n",
    "batch_size = 128\n",
    "ou_noise_theta = 1.0\n",
    "ou_noise_sigma = 0.1\n",
    "initial_random_steps = 10000\n",
    "n_step = 3\n",
    "pretrain_step = 1000\n",
    "\n",
    "agent = DDPGfDAgent(\n",
    "    env, \n",
    "    memory_size, \n",
    "    batch_size,\n",
    "    ou_noise_theta,\n",
    "    ou_noise_sigma,\n",
    "    demo,\n",
    "    n_step=n_step,\n",
    "    pretrain_step=pretrain_step,\n",
    "    initial_random_steps=initial_random_steps,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 2160x360 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "agent.train(num_frames)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test\n",
    "Run the trained agent (1 episode)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:  -232.4411445000226\n"
     ]
    }
   ],
   "source": [
    "# test\n",
    "if IN_COLAB:\n",
    "    agent.env = gym.wrappers.Monitor(agent.env, \"videos\", force=True)\n",
    "frames = agent.test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Render"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Define the Animation class */\n",
       "  function Animation(frames, img_id, slider_id, interval, loop_select_id){\n",
       "    this.img_id = img_id;\n",
       "    this.slider_id = slider_id;\n",
       "    this.loop_select_id = loop_select_id;\n",
       "    this.interval = interval;\n",
       "    this.current_frame = 0;\n",
       "    this.direction = 0;\n",
       "    this.timer = null;\n",
       "    this.frames = new Array(frames.length);\n",
       "\n",
       "    for (var i=0; i<frames.length; i++)\n",
       "    {\n",
       "     this.frames[i] = new Image();\n",
       "     this.frames[i].src = frames[i];\n",
       "    }\n",
       "    document.getElementById(this.slider_id).max = this.frames.length - 1;\n",
       "    this.set_frame(this.current_frame);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.get_loop_state = function(){\n",
       "    var button_group = document[this.loop_select_id].state;\n",
       "    for (var i = 0; i < button_group.length; i++) {\n",
       "        var button = button_group[i];\n",
       "        if (button.checked) {\n",
       "            return button.value;\n",
       "        }\n",
       "    }\n",
       "    return undefined;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.set_frame = function(frame){\n",
       "    this.current_frame = frame;\n",
       "    document.getElementById(this.img_id).src = this.frames[this.current_frame].src;\n",
       "    document.getElementById(this.slider_id).value = this.current_frame;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.next_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.previous_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.max(0, this.current_frame - 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.first_frame = function()\n",
       "  {\n",
       "    this.set_frame(0);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.last_frame = function()\n",
       "  {\n",
       "    this.set_frame(this.frames.length - 1);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.slower = function()\n",
       "  {\n",
       "    this.interval /= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.faster = function()\n",
       "  {\n",
       "    this.interval *= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_forward = function()\n",
       "  {\n",
       "    this.current_frame += 1;\n",
       "    if(this.current_frame < this.frames.length){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.first_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.last_frame();\n",
       "        this.reverse_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.last_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_reverse = function()\n",
       "  {\n",
       "    this.current_frame -= 1;\n",
       "    if(this.current_frame >= 0){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.last_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.first_frame();\n",
       "        this.play_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.first_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.pause_animation = function()\n",
       "  {\n",
       "    this.direction = 0;\n",
       "    if (this.timer){\n",
       "      clearInterval(this.timer);\n",
       "      this.timer = null;\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.play_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = 1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.reverse_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = -1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n",
       "  }\n",
       "</script>\n",
       "\n",
       "<div class=\"animation\" align=\"center\">\n",
       "    <img id=\"_anim_imgUSEVRZLNVGZPLVUR\">\n",
       "    <br>\n",
       "    <input id=\"_anim_sliderUSEVRZLNVGZPLVUR\" type=\"range\" style=\"width:350px\" name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\" onchange=\"animUSEVRZLNVGZPLVUR.set_frame(parseInt(this.value));\"></input>\n",
       "    <br>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.slower()\">&#8211;</button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.first_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.previous_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.reverse_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.pause_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.play_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.next_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.last_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animUSEVRZLNVGZPLVUR.faster()\">+</button>\n",
       "  <form action=\"#n\" name=\"_anim_loop_selectUSEVRZLNVGZPLVUR\" class=\"anim_control\">\n",
       "    <input type=\"radio\" name=\"state\" value=\"once\" > Once </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"loop\" checked> Loop </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"reflect\" > Reflect </input>\n",
       "  </form>\n",
       "</div>\n",
       "\n",
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Instantiate the Animation class. */\n",
       "  /* The IDs given should match those used in the template above. */\n",
       "  (function() {\n",
       "    var img_id = \"_anim_imgUSEVRZLNVGZPLVUR\";\n",
       "    var slider_id = \"_anim_sliderUSEVRZLNVGZPLVUR\";\n",
       "    var loop_select_id = \"_anim_loop_selectUSEVRZLNVGZPLVUR\";\n",
       "    var frames = new Array(0);\n",
       "    \n",
       "  frames[0] = \"\"\n",
       "  frames[1] = \"\"\n",
       "  frames[2] = \"\"\n",
       "  frames[3] = \"\"\n",
       "  frames[4] = \"\"\n",
       "  frames[5] = \"\"\n",
       "  frames[6] = \"\"\n",
       "  frames[7] = \"\"\n",
       "  frames[8] = \"\"\n",
       "  frames[9] = \"\"\n",
       "  frames[10] = \"\"\n",
       "  frames[11] = \"\"\n",
       "  frames[12] = \"\"\n",
       "  frames[13] = \"\"\n",
       "  frames[14] = \"\"\n",
       "  frames[15] = \"\"\n",
       "  frames[16] = \"\"\n",
       "  frames[17] = \"\"\n",
       "  frames[18] = \"\"\n",
       "  frames[19] = \"\"\n",
       "  frames[20] = \"\"\n",
       "  frames[21] = \"\"\n",
       "  frames[22] = \"\"\n",
       "  frames[23] = \"\"\n",
       "  frames[24] = \"\"\n",
       "  frames[25] = \"\"\n",
       "  frames[26] = \"\"\n",
       "  frames[27] = \"\"\n",
       "  frames[28] = \"\"\n",
       "  frames[29] = \"\"\n",
       "  frames[30] = \"\"\n",
       "  frames[31] = \"\"\n",
       "  frames[32] = \"\"\n",
       "  frames[33] = \"\"\n",
       "  frames[34] = \"\"\n",
       "  frames[35] = \"\"\n",
       "  frames[36] = \"\"\n",
       "  frames[37] = \"\"\n",
       "  frames[38] = \"\"\n",
       "  frames[39] = \"\"\n",
       "  frames[40] = \"\"\n",
       "  frames[41] = \"\"\n",
       "  frames[42] = \"\"\n",
       "  frames[43] = \"\"\n",
       "  frames[44] = \"\"\n",
       "  frames[45] = \"\"\n",
       "  frames[46] = \"\"\n",
       "  frames[47] = \"\"\n",
       "  frames[48] = \"\"\n",
       "  frames[49] = \"\"\n",
       "  frames[50] = \"\"\n",
       "  frames[51] = \"\"\n",
       "  frames[52] = \"\"\n",
       "  frames[53] = \"\"\n",
       "  frames[54] = \"\"\n",
       "  frames[55] = \"\"\n",
       "  frames[56] = \"\"\n",
       "  frames[57] = \"\"\n",
       "  frames[58] = \"\"\n",
       "  frames[59] = \"\"\n",
       "  frames[60] = \"\"\n",
       "  frames[61] = \"\"\n",
       "  frames[62] = \"\"\n",
       "  frames[63] = \"\"\n",
       "  frames[64] = \"\"\n",
       "  frames[65] = \"\"\n",
       "  frames[66] = \"\"\n",
       "  frames[67] = \"\"\n",
       "  frames[68] = \"\"\n",
       "  frames[69] = \"\"\n",
       "  frames[70] = \"\"\n",
       "  frames[71] = \"\"\n",
       "  frames[72] = \"\"\n",
       "  frames[73] = \"\"\n",
       "  frames[74] = \"\"\n",
       "  frames[75] = \"\"\n",
       "  frames[76] = \"\"\n",
       "  frames[77] = \"\"\n",
       "  frames[78] = \"\"\n",
       "  frames[79] = \"\"\n",
       "  frames[80] = \"\"\n",
       "  frames[81] = \"\"\n",
       "  frames[82] = \"\"\n",
       "  frames[83] = \"\"\n",
       "  frames[84] = \"\"\n",
       "  frames[85] = \"\"\n",
       "  frames[86] = \"\"\n",
       "  frames[87] = \"\"\n",
       "  frames[88] = \"\"\n",
       "  frames[89] = \"\"\n",
       "  frames[90] = \"\"\n",
       "  frames[91] = \"\"\n",
       "  frames[92] = \"\"\n",
       "  frames[93] = \"\"\n",
       "  frames[94] = \"\"\n",
       "  frames[95] = \"\"\n",
       "  frames[96] = \"\"\n",
       "  frames[97] = \"\"\n",
       "  frames[98] = \"\"\n",
       "  frames[99] = \"\"\n",
       "  frames[100] = \"\"\n",
       "  frames[101] = \"\"\n",
       "  frames[102] = \"\"\n",
       "  frames[103] = \"\"\n",
       "  frames[104] = \"\"\n",
       "  frames[105] = \"\"\n",
       "  frames[106] = \"\"\n",
       "  frames[107] = \"\"\n",
       "  frames[108] = \"\"\n",
       "  frames[109] = \"\"\n",
       "  frames[110] = \"\"\n",
       "  frames[111] = \"\"\n",
       "  frames[112] = \"\"\n",
       "  frames[113] = \"\"\n",
       "  frames[114] = \"\"\n",
       "  frames[115] = \"\"\n",
       "  frames[116] = \"\"\n",
       "  frames[117] = \"\"\n",
       "  frames[118] = \"\"\n",
       "  frames[119] = \"\"\n",
       "  frames[120] = \"\"\n",
       "  frames[121] = \"\"\n",
       "  frames[122] = \"\"\n",
       "  frames[123] = \"\"\n",
       "  frames[124] = \"\"\n",
       "  frames[125] = \"\"\n",
       "  frames[126] = \"\"\n",
       "  frames[127] = \"\"\n",
       "  frames[128] = \"\"\n",
       "  frames[129] = \"\"\n",
       "  frames[130] = \"\"\n",
       "  frames[131] = \"\"\n",
       "  frames[132] = \"\"\n",
       "  frames[133] = \"\"\n",
       "  frames[134] = \"\"\n",
       "  frames[135] = \"\"\n",
       "  frames[136] = \"\"\n",
       "  frames[137] = \"\"\n",
       "  frames[138] = \"\"\n",
       "  frames[139] = \"\"\n",
       "  frames[140] = \"\"\n",
       "  frames[141] = \"\"\n",
       "  frames[142] = \"\"\n",
       "  frames[143] = \"\"\n",
       "  frames[144] = \"\"\n",
       "  frames[145] = \"\"\n",
       "  frames[146] = \"\"\n",
       "  frames[147] = \"\"\n",
       "  frames[148] = \"\"\n",
       "  frames[149] = \"\"\n",
       "  frames[150] = \"\"\n",
       "  frames[151] = \"\"\n",
       "  frames[152] = \"\"\n",
       "  frames[153] = \"\"\n",
       "  frames[154] = \"\"\n",
       "  frames[155] = \"\"\n",
       "  frames[156] = \"\"\n",
       "  frames[157] = \"\"\n",
       "  frames[158] = \"\"\n",
       "  frames[159] = \"\"\n",
       "  frames[160] = \"\"\n",
       "  frames[161] = \"\"\n",
       "  frames[162] = \"\"\n",
       "  frames[163] = \"\"\n",
       "  frames[164] = \"\"\n",
       "  frames[165] = \"\"\n",
       "  frames[166] = \"\"\n",
       "  frames[167] = \"\"\n",
       "  frames[168] = \"\"\n",
       "  frames[169] = \"\"\n",
       "  frames[170] = \"\"\n",
       "  frames[171] = \"\"\n",
       "  frames[172] = \"\"\n",
       "  frames[173] = \"\"\n",
       "  frames[174] = \"\"\n",
       "  frames[175] = \"\"\n",
       "  frames[176] = \"\"\n",
       "  frames[177] = \"\"\n",
       "  frames[178] = \"\"\n",
       "  frames[179] = \"\"\n",
       "  frames[180] = \"\"\n",
       "  frames[181] = \"\"\n",
       "  frames[182] = \"\"\n",
       "  frames[183] = \"\"\n",
       "  frames[184] = \"\"\n",
       "  frames[185] = \"\"\n",
       "  frames[186] = \"\"\n",
       "  frames[187] = \"\"\n",
       "  frames[188] = \"\"\n",
       "  frames[189] = \"\"\n",
       "  frames[190] = \"\"\n",
       "  frames[191] = \"\"\n",
       "  frames[192] = \"\"\n",
       "  frames[193] = \"\"\n",
       "  frames[194] = \"\"\n",
       "  frames[195] = \"\"\n",
       "  frames[196] = \"\"\n",
       "  frames[197] = \"\"\n",
       "  frames[198] = \"\"\n",
       "  frames[199] = \"\"\n",
       "\n",
       "\n",
       "    /* set a timeout to make sure all the above elements are created before\n",
       "       the object is initialized. */\n",
       "    setTimeout(function() {\n",
       "        animUSEVRZLNVGZPLVUR = new Animation(frames, img_id, slider_id, 50, loop_select_id);\n",
       "    }, 0);\n",
       "  })()\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if IN_COLAB:  # for colab\n",
    "    import base64\n",
    "    import glob\n",
    "    import io\n",
    "    import os\n",
    "\n",
    "    from IPython.display import HTML, display\n",
    "\n",
    "    def ipython_show_video(path: str) -> None:\n",
    "        \"\"\"Show a video at `path` within IPython Notebook.\"\"\"\n",
    "        if not os.path.isfile(path):\n",
    "            raise NameError(\"Cannot access: {}\".format(path))\n",
    "\n",
    "        video = io.open(path, \"r+b\").read()\n",
    "        encoded = base64.b64encode(video)\n",
    "\n",
    "        display(HTML(\n",
    "            data=\"\"\"\n",
    "            <video alt=\"test\" controls>\n",
    "            <source src=\"data:video/mp4;base64,{0}\" type=\"video/mp4\"/>\n",
    "            </video>\n",
    "            \"\"\".format(encoded.decode(\"ascii\"))\n",
    "        ))\n",
    "\n",
    "    list_of_files = glob.glob(\"videos/*.mp4\")\n",
    "    latest_file = max(list_of_files, key=os.path.getctime)\n",
    "    print(latest_file)\n",
    "    ipython_show_video(latest_file)\n",
    "\n",
    "else:  # for jupyter\n",
    "    from matplotlib import animation\n",
    "    from JSAnimation.IPython_display import display_animation\n",
    "    from IPython.display import display\n",
    "\n",
    "\n",
    "    def display_frames_as_gif(frames):\n",
    "        \"\"\"Displays a list of frames as a gif, with controls.\"\"\"\n",
    "        patch = plt.imshow(frames[0])\n",
    "        plt.axis('off')\n",
    "\n",
    "        def animate(i):\n",
    "            patch.set_data(frames[i])\n",
    "\n",
    "        anim = animation.FuncAnimation(\n",
    "            plt.gcf(), animate, frames = len(frames), interval=50\n",
    "        )\n",
    "        display(display_animation(anim, default_mode='loop'))\n",
    "\n",
    "\n",
    "    # display \n",
    "    display_frames_as_gif(frames)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pg-is-all-you-need",
   "language": "python",
   "name": "pg-is-all-you-need"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
